import { useRef, useCallback, useEffect } from 'react';

interface DragConfig {
  position: { x: number; y: number };
  size: { width: number; height: number };
}

interface DragOptions {
  onDragEnd?: (position: { x: number; y: number }) => void;
  edgeSnapThreshold?: number;
  animationDuration?: number;
  ballSize?: number;
}

interface DragState {
  isDragging: boolean;
  startX: number;
  startY: number;
  offsetX: number;
  offsetY: number;
  ballSize: number;
}

export const useDraggable = (
  config: DragConfig,
  options: DragOptions = {}
) => {
  const {
    onDragEnd,
    edgeSnapThreshold = 20,
    animationDuration = 300,
    ballSize = 60
  } = options;

  const elementRef = useRef<HTMLDivElement>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  
  // 拖动相关的ref，避免状态更新延迟
  const dragDataRef = useRef<DragState>({
    isDragging: false,
    startX: 0,
    startY: 0,
    offsetX: 0,
    offsetY: 0,
    ballSize
  });

  // 当前位置的ref，用于原生DOM操作
  const currentPositionRef = useRef({
    x: config.position.x,
    y: config.position.y
  });

  // 边缘吸附动画函数
  const animateToPosition = useCallback((targetX: number, targetY: number) => {
    if (!elementRef.current) return;
    
    const startX = currentPositionRef.current.x;
    const startY = currentPositionRef.current.y;
    const startTime = performance.now();
    
    const animate = (currentTime: number) => {
      const elapsed = currentTime - startTime;
      const progress = Math.min(elapsed / animationDuration, 1);
      
      // 使用缓动函数实现平滑动画
      const easeOutCubic = 1 - Math.pow(1 - progress, 3);
      
      const currentX = startX + (targetX - startX) * easeOutCubic;
      const currentY = startY + (targetY - startY) * easeOutCubic;
      
      if (elementRef.current) {
        elementRef.current.style.left = currentX + 'px';
        elementRef.current.style.top = currentY + 'px';
      }
      
      currentPositionRef.current.x = currentX;
      currentPositionRef.current.y = currentY;
      
      // 同步更新面板位置
      if (panelRef.current) {
        const panelLeft = Math.max(10, currentX - config.size.width + 60);
        panelRef.current.style.left = panelLeft + 'px';
        panelRef.current.style.top = currentY + 'px';
      }
      
      if (progress < 1) {
        requestAnimationFrame(animate);
      } else {
        // 动画完成，触发回调
        onDragEnd?.({ x: targetX, y: targetY });
      }
    };
    
    requestAnimationFrame(animate);
  }, [animationDuration, config.size.width, onDragEnd]);

  // 计算边缘吸附位置
  const calculateSnapPosition = useCallback((x: number, y: number) => {
    const screenWidth = window.innerWidth;
    const screenHeight = window.innerHeight;
    const ballSize = dragDataRef.current.ballSize;
    
    let snapX = x;
    let snapY = y;
    
    // 左右边缘吸附
    if (x < edgeSnapThreshold) {
      snapX = 0;
    } else if (x > screenWidth - ballSize - edgeSnapThreshold) {
      snapX = screenWidth - ballSize;
    }
    
    // 上下边缘吸附（通常不吸附下边缘，避免遮挡任务栏）
    if (y < edgeSnapThreshold) {
      snapY = 0;
    }
    
    return { x: snapX, y: snapY };
  }, [edgeSnapThreshold]);

  // 原生 drag API 事件处理
  const handleDragStart = useCallback((e: DragEvent) => {
    if (!elementRef.current) return;
    
    // 隐藏拖动影像
    if (e.dataTransfer) {
      e.dataTransfer.effectAllowed = 'move';
      e.dataTransfer.setData('text/plain', '');
      // 创建透明的拖动影像
      const canvas = document.createElement('canvas');
      canvas.width = canvas.height = 1;
      const ctx = canvas.getContext('2d');
      if (ctx) {
        ctx.globalAlpha = 0;
        ctx.fillRect(0, 0, 1, 1);
      }
      e.dataTransfer.setDragImage(canvas, 0, 0);
    }
    
    const rect = elementRef.current.getBoundingClientRect();
    
    // 记录拖动开始的偏移量
    dragDataRef.current = {
      isDragging: true,
      startX: e.clientX,
      startY: e.clientY,
      offsetX: e.clientX - rect.left,
      offsetY: e.clientY - rect.top,
      ballSize
    };
    
    // 更新当前位置引用
    currentPositionRef.current.x = rect.left;
    currentPositionRef.current.y = rect.top;
    
    // 添加拖动状态样式
    elementRef.current.classList.add('dragging');
  }, [ballSize]);

  const handleDrag = useCallback((e: DragEvent) => {
    if (!dragDataRef.current.isDragging || !elementRef.current) return;
    
    // drag事件在拖动结束时clientX/Y会变为0，需要忽略
    if (e.clientX === 0 && e.clientY === 0) return;
    
    // 直接计算新位置
    const newX = e.clientX - dragDataRef.current.offsetX;
    const newY = e.clientY - dragDataRef.current.offsetY;
    
    // 边界检查
    const maxX = window.innerWidth - dragDataRef.current.ballSize;
    const maxY = window.innerHeight - dragDataRef.current.ballSize;
    
    const clampedX = Math.max(0, Math.min(newX, maxX));
    const clampedY = Math.max(0, Math.min(newY, maxY));
    
    // 直接更新DOM位置
    elementRef.current.style.left = clampedX + 'px';
    elementRef.current.style.top = clampedY + 'px';
    
    // 更新位置引用
    currentPositionRef.current.x = clampedX;
    currentPositionRef.current.y = clampedY;
    
    // 同步更新面板位置
    if (panelRef.current) {
      const panelLeft = Math.max(10, clampedX - config.size.width + 60);
      panelRef.current.style.left = panelLeft + 'px';
      panelRef.current.style.top = clampedY + 'px';
    }
  }, [config.size.width]);

  const handleDragEnd = useCallback((e: DragEvent) => {
    if (!dragDataRef.current.isDragging) return;
    
    dragDataRef.current.isDragging = false;
    
    const currentX = currentPositionRef.current.x;
    const currentY = currentPositionRef.current.y;
    
    // 检查是否需要边缘吸附
    const snapPosition = calculateSnapPosition(currentX, currentY);
    
    // 如果需要吸附，执行动画
    const needsSnap = snapPosition.x !== currentX || snapPosition.y !== currentY;
    
    if (needsSnap) {
      // 边缘吸附动画
      animateToPosition(snapPosition.x, snapPosition.y);
    } else {
      // 没有动画，直接触发回调
      onDragEnd?.({ x: currentX, y: currentY });
    }
    
    // 移除拖动状态样式
    if (elementRef.current) {
      elementRef.current.classList.remove('dragging');
    }
  }, [calculateSnapPosition, animateToPosition, onDragEnd]);

  // 绑定原生drag事件到元素
  useEffect(() => {
    const element = elementRef.current;
    if (!element) return;

    // 设置元素可拖拽
    element.draggable = true;
    
    // 绑定drag事件
    element.addEventListener('dragstart', handleDragStart);
    element.addEventListener('drag', handleDrag);
    element.addEventListener('dragend', handleDragEnd);

    return () => {
      // 清理事件监听器
      element.removeEventListener('dragstart', handleDragStart);
      element.removeEventListener('drag', handleDrag);
      element.removeEventListener('dragend', handleDragEnd);
    };
  }, [handleDragStart, handleDrag, handleDragEnd]);

  // 监听窗口大小变化，调整悬浮球位置
  useEffect(() => {
    const handleResize = () => {
      const maxX = window.innerWidth - dragDataRef.current.ballSize;
      const maxY = window.innerHeight - dragDataRef.current.ballSize;
      
      const newX = Math.max(0, Math.min(currentPositionRef.current.x, maxX));
      const newY = Math.max(0, Math.min(currentPositionRef.current.y, maxY));
      
      if (newX !== currentPositionRef.current.x || newY !== currentPositionRef.current.y) {
        currentPositionRef.current.x = newX;
        currentPositionRef.current.y = newY;
        
        // 直接更新DOM位置
        if (elementRef.current) {
          elementRef.current.style.left = newX + 'px';
          elementRef.current.style.top = newY + 'px';
        }
        
        // 触发回调通知位置变化
        onDragEnd?.({ x: newX, y: newY });
      }
    };
    
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, [onDragEnd]);

  // 同步初始位置
  useEffect(() => {
    currentPositionRef.current.x = config.position.x;
    currentPositionRef.current.y = config.position.y;
  }, [config.position.x, config.position.y]);

  return {
    elementRef,
    panelRef,
    isDragging: dragDataRef.current.isDragging,
    currentPosition: currentPositionRef.current
  };
};